{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9b445f24",
   "metadata": {},
   "source": [
    "模拟数据集中的动作,就是传统的深度学习而已"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e1fe6ad8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(20000, (tensor([-0.0028,  0.0180, -0.0188, -0.0368]), tensor(0)))"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "\n",
    "#封装数据集\n",
    "class Dataset(torch.utils.data.Dataset):\n",
    "\n",
    "    def __init__(self):\n",
    "        import numpy as np\n",
    "        data = np.loadtxt('离散动作.txt')\n",
    "        self.state = torch.FloatTensor(data[:, :4])\n",
    "        self.action = torch.LongTensor(data[:, -1])\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.state)\n",
    "\n",
    "    def __getitem__(self, i):\n",
    "        return self.state[i], self.action[i]\n",
    "\n",
    "\n",
    "dataset = Dataset()\n",
    "\n",
    "len(dataset), dataset[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b37e9edc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2500,\n",
       " [tensor([[ 1.5843e-01, -5.3389e-02,  2.4347e-04,  1.3181e-01],\n",
       "          [ 1.5329e-01,  1.9470e-01,  4.8345e-03, -2.3730e-01],\n",
       "          [ 1.6449e-01,  1.5640e-01,  8.6902e-04, -1.7631e-01],\n",
       "          [ 5.2323e-02,  1.6990e-01,  1.5965e-03, -1.8915e-01],\n",
       "          [ 7.1826e-02, -3.7482e-02, -1.0227e-02,  1.6802e-01],\n",
       "          [ 9.2822e-02,  1.5960e-01,  9.0184e-03, -1.6790e-01],\n",
       "          [ 1.3534e-01, -2.3736e-01,  2.2018e-02,  3.8089e-01],\n",
       "          [ 3.7986e-02, -1.7835e-02, -2.2120e-03,  1.0894e-01]]),\n",
       "  tensor([1, 0, 0, 0, 1, 0, 1, 1])])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#数据加载器\n",
    "loader = torch.utils.data.DataLoader(dataset=dataset,\n",
    "                                     batch_size=8,\n",
    "                                     shuffle=True,\n",
    "                                     drop_last=True)\n",
    "\n",
    "len(loader), next(iter(loader))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9e2a4f3f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([2, 2])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#定义模型\n",
    "model = torch.nn.Sequential(\n",
    "    torch.nn.Linear(4, 64),\n",
    "    torch.nn.ReLU(),\n",
    "    torch.nn.Linear(64, 64),\n",
    "    torch.nn.ReLU(),\n",
    "    torch.nn.Linear(64, 2),\n",
    ")\n",
    "\n",
    "model(torch.randn(2, 4)).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f9c86086",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0.23804855346679688 0.875\n",
      "1 0.23378416895866394 1.0\n",
      "2 0.6556164622306824 0.75\n",
      "3 0.14761586487293243 1.0\n",
      "4 0.2092546820640564 1.0\n",
      "5 0.12375369668006897 1.0\n",
      "6 0.16725218296051025 0.875\n",
      "7 0.3405707776546478 0.875\n",
      "8 0.0441044345498085 1.0\n",
      "9 0.7327598333358765 0.875\n"
     ]
    }
   ],
   "source": [
    "#训练\n",
    "def train():\n",
    "    model.train()\n",
    "    optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\n",
    "    loss_fn = torch.nn.CrossEntropyLoss()\n",
    "\n",
    "    for epoch in range(10):\n",
    "        for i, (state, action) in enumerate(loader):\n",
    "            out = model(state)\n",
    "\n",
    "            loss = loss_fn(out, action)\n",
    "            loss.backward()\n",
    "            optimizer.step()\n",
    "            optimizer.zero_grad()\n",
    "\n",
    "        if epoch % 1 == 0:\n",
    "            out = out.argmax(dim=1)\n",
    "            acc = (out == action).sum().item() / len(action)\n",
    "            print(epoch, loss.item(), acc)\n",
    "\n",
    "\n",
    "train()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "827e5290",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 300x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import gym\n",
    "\n",
    "\n",
    "#定义环境\n",
    "class MyWrapper(gym.Wrapper):\n",
    "\n",
    "    def __init__(self):\n",
    "        env = gym.make('CartPole-v1', render_mode='rgb_array')\n",
    "        super().__init__(env)\n",
    "        self.env = env\n",
    "        self.step_n = 0\n",
    "\n",
    "    def reset(self):\n",
    "        state, _ = self.env.reset()\n",
    "        self.step_n = 0\n",
    "        return state\n",
    "\n",
    "    def step(self, action):\n",
    "        state, reward, terminated, truncated, info = self.env.step(action)\n",
    "        over = terminated or truncated\n",
    "\n",
    "        #限制最大步数\n",
    "        self.step_n += 1\n",
    "        if self.step_n >= 200:\n",
    "            over = True\n",
    "        \n",
    "        #没坚持到最后,扣分\n",
    "        if over and self.step_n < 200:\n",
    "            reward = -1000\n",
    "\n",
    "        return state, reward, over\n",
    "\n",
    "    #打印游戏图像\n",
    "    def show(self):\n",
    "        from matplotlib import pyplot as plt\n",
    "        plt.figure(figsize=(3, 3))\n",
    "        plt.imshow(self.env.render())\n",
    "        plt.show()\n",
    "\n",
    "\n",
    "env = MyWrapper()\n",
    "\n",
    "env.reset()\n",
    "\n",
    "env.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3ed91503",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "200.0"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython import display\n",
    "import random\n",
    "\n",
    "\n",
    "#玩一局游戏并记录数据\n",
    "def play(show=False):\n",
    "    reward_sum = 0\n",
    "\n",
    "    state = env.reset()\n",
    "    over = False\n",
    "    while not over:\n",
    "        action = model(torch.FloatTensor(state).reshape(1, 4)).argmax().item()\n",
    "        if random.random() < 0.1:\n",
    "            action = env.action_space.sample()\n",
    "\n",
    "        state, reward, over = env.step(action)\n",
    "        reward_sum += reward\n",
    "\n",
    "        if show:\n",
    "            display.clear_output(wait=True)\n",
    "            env.show()\n",
    "\n",
    "    return reward_sum\n",
    "\n",
    "\n",
    "#测试\n",
    "sum([play() for _ in range(20)]) / 20"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ad416500",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 300x300 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "200.0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "play(True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:pt39]",
   "language": "python",
   "name": "conda-env-pt39-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
